From e1cdb09708ce6d363238a06782eb10c52354ac9a Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Sat, 6 Mar 2004 14:57:12 +0000 Subject: [PATCH] bitkeeper revision 1.770 (4049e6c8Y4j_un8mTZVBzW2v2v9zjQ) console.c: new file Many files: Redirect to DOM0 linux to new serial io interface. Deprecated HYPERVISOR_console_write. .del-printk.c~67ddc78b3f262afa: Delete: xenolinux-2.4.25-sparse/kernel/printk.c .del-console.c~cc66a22964db9adc: Delete: xen/common/console.c keyboard.c: Rename: xen/drivers/char/xen_kbd.c -> xen/drivers/char/keyboard.c --- .rootkeys | 5 +- xen/arch/i386/entry.S | 1 + xen/common/console.c | 29 - xen/common/dom0_ops.c | 3 +- xen/common/domain.c | 5 +- xen/common/kernel.c | 316 +------- xen/common/keyhandler.c | 9 - xen/drivers/char/console.c | 498 +++++++++++++ xen/drivers/char/{xen_kbd.c => keyboard.c} | 8 + xen/include/hypervisor-ifs/hypervisor-if.h | 9 +- xen/include/xeno/console.h | 23 +- .../arch/xeno/drivers/console/console.c | 18 +- .../include/asm-xeno/hypervisor.h | 25 +- .../include/asm-xeno/processor.h | 4 +- xenolinux-2.4.25-sparse/kernel/panic.c | 1 - xenolinux-2.4.25-sparse/kernel/printk.c | 703 ------------------ 16 files changed, 552 insertions(+), 1105 deletions(-) delete mode 100644 xen/common/console.c create mode 100644 xen/drivers/char/console.c rename xen/drivers/char/{xen_kbd.c => keyboard.c} (97%) delete mode 100644 xenolinux-2.4.25-sparse/kernel/printk.c diff --git a/.rootkeys b/.rootkeys index c7c8cc4010..71702d606d 100644 --- a/.rootkeys +++ b/.rootkeys @@ -134,7 +134,6 @@ 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c 3ddb79bdrqnW93GR9gZk1OJe1qK-iQ xen/common/brlock.c -3fb10d07GscSWPKxBqpvNfU-dYfa0g xen/common/console.c 4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c 3fa152581E5KhrAtqZef2Sr5NKTz4w xen/common/debug.c 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c @@ -175,8 +174,9 @@ 3e9c248afxxsnAzIt2na7Ej24yNFzg xen/drivers/cdrom/Makefile 3e9c248ajUkn2W3n4vgm72Hp2ftZ8A xen/drivers/cdrom/cdrom.c 3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen/drivers/char/Makefile +4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c +3e4a8cb7WmiYdC-ASGiCSG_CL8vsqg xen/drivers/char/keyboard.c 3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c -3e4a8cb7WmiYdC-ASGiCSG_CL8vsqg xen/drivers/char/xen_kbd.c 3ddb79bdhcqD9ebrslr0O0oHqTiiXg xen/drivers/ide/Makefile 3e9c248aCM6Lex1Am8_NJIeesN4kKg xen/drivers/ide/ide-cd.c 3e9c248aFfSNR_hl-WQBbv-R9CTgzg xen/drivers/ide/ide-cd.h @@ -599,7 +599,6 @@ 401c0592pLrp_aCbQRo9GXiYQQaVVA xenolinux-2.4.25-sparse/include/linux/timer.h 3e5a4e68W_hpMlM3u_-QOKMp3gzcwQ xenolinux-2.4.25-sparse/init/do_mounts.c 3e5a4e68TJJavrunYwTAnLRSBxSYqQ xenolinux-2.4.25-sparse/kernel/panic.c -3f1056a9LXNTgSzITNh1mb-MIKV1Ng xenolinux-2.4.25-sparse/kernel/printk.c 3f9d4b44247udoqWEgFkaHiWv6Uvyg xenolinux-2.4.25-sparse/kernel/time.c 401c059bjLBFYHRD4Py2uM3eA1D4zQ xenolinux-2.4.25-sparse/kernel/timer.c 3eba8f878XjouY21EkQBXwYBsPsipQ xenolinux-2.4.25-sparse/lndir-rel diff --git a/xen/arch/i386/entry.S b/xen/arch/i386/entry.S index c1c57ac11d..bc0fc732a8 100644 --- a/xen/arch/i386/entry.S +++ b/xen/arch/i386/entry.S @@ -727,6 +727,7 @@ ENTRY(hypervisor_call_table) .long SYMBOL_NAME(do_set_timer_op) /* 20 */ .long SYMBOL_NAME(do_event_channel_op) .long SYMBOL_NAME(do_xen_version) + .long SYMBOL_NAME(do_serial_io) .rept NR_syscalls-((.-hypervisor_call_table)/4) .long SYMBOL_NAME(do_ni_syscall) .endr diff --git a/xen/common/console.c b/xen/common/console.c deleted file mode 100644 index d52a8cf3be..0000000000 --- a/xen/common/console.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * console.c - * - * read domain console output buffer ring in Xen - * - */ - -#include -#include - -console_ring_t console_ring = { - .len = 0 -}; - -long read_console_ring(unsigned long str, unsigned int count, unsigned cmd) -{ - unsigned int len; - - len = (console_ring.len < count) ? console_ring.len : count; - - if ( copy_to_user((char *)str, console_ring.buf, len) ) - return -EFAULT; - - if ( cmd & CONSOLE_RING_CLEAR ) { - console_ring.len = 0; - } - - return len; -} diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 45f11108cc..11e755e65d 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -17,6 +17,7 @@ #include #include #include +#include extern unsigned int alloc_new_dom_mem(struct task_struct *, unsigned int); @@ -443,8 +444,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) case DOM0_READCONSOLE: { - extern long read_console_ring(unsigned long, - unsigned int, unsigned int); ret = read_console_ring(op->u.readconsole.str, op->u.readconsole.count, op->u.readconsole.cmd); diff --git a/xen/common/domain.c b/xen/common/domain.c index 8186248dc8..d226c52d5f 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -806,9 +806,8 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params, } *dst = '\0'; - /* HACK: Give up the VGA console iff the Xenolinux DOM0 wants it. */ - if ( strstr(cmdline, "tty0") != NULL ) - vgacon_enabled = 0; + /* NB: Give up the VGA console iff the Xenolinux DOM0 wants it. */ + console_endboot(strstr(cmdline, "tty0") != NULL); /* Reinstate the caller's page tables. */ write_cr3_counted(pagetable_val(current->mm.pagetable)); diff --git a/xen/common/kernel.c b/xen/common/kernel.c index a906786c42..055316e7a7 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -33,21 +34,12 @@ kmem_cache_t *task_struct_cachep; -static int xpos, ypos; -static unsigned char *video = __va(0xB8000); - -int sercon_handle = -1; -int vgacon_enabled = 0; - -spinlock_t console_lock = SPIN_LOCK_UNLOCKED; - struct e820entry { unsigned long addr_lo, addr_hi; /* start of memory segment */ unsigned long size_lo, size_hi; /* size of memory segment */ unsigned long type; /* type of memory segment */ }; -static void init_vga(void); void start_of_day(void); /* opt_console: comma-separated list of console outputs. */ @@ -108,7 +100,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) struct task_struct *new_dom; dom0_createdomain_t dom0_params; unsigned long max_page; - unsigned char *cmdline, *p; + unsigned char *cmdline; module_t *mod; void *heap_start; int i; @@ -162,19 +154,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) /* We initialise the serial devices very early so we can get debugging. */ serial_init_stage1(); - /* Where should console output go? */ - for ( p = opt_console; p != NULL; p = strchr(p, ',') ) - { - if ( *p == ',' ) - p++; - if ( strncmp(p, "com", 3) == 0 ) - sercon_handle = parse_serial_handle(p); - else if ( strncmp(p, "vga", 3) == 0 ) - vgacon_enabled = 1; - } - - /* Set up VGA console output, if it was enabled. */ - init_vga(); + init_console(); /* HELLO WORLD --- start-of-day banner text. */ printk(XEN_BANNER); @@ -184,6 +164,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION, XEN_COMPILE_BY, XEN_COMPILE_DOMAIN, XEN_COMPILER, XEN_COMPILE_DATE); + set_printk_prefix("(XEN) "); if ( opt_ser_baud != 0 ) printk("**WARNING**: Xen option 'ser_baud=' is deprecated! " @@ -266,294 +247,7 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) startup_cpu_idle_loop(); } - -/********************************* - * Various console code follows... - */ - -/* VGA text (mode 3) definitions. */ -#define COLUMNS 80 -#define LINES 25 -#define ATTRIBUTE 7 - -/* Clear the screen and initialize VIDEO, XPOS and YPOS. */ -static void cls(void) -{ - memset(video, 0, COLUMNS * LINES * 2); - xpos = ypos = 0; - outw(10+(1<<(5+8)), 0x3d4); /* cursor off */ -} - -static int detect_video(void *video_base) -{ - volatile u16 *p = (volatile u16 *)video_base; - u16 saved1 = p[0], saved2 = p[1]; - int video_found = 1; - - p[0] = 0xAA55; - p[1] = 0x55AA; - if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) ) - video_found = 0; - - p[0] = 0x55AA; - p[1] = 0xAA55; - if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) ) - video_found = 0; - - p[0] = saved1; - p[1] = saved2; - - return video_found; -} - -static int detect_vga(void) -{ - /* - * Look at a number of well-known locations. Even if video is not at - * 0xB8000 right now, it will appear there when we set up text mode 3. - * - * We assume if there is any sign of a video adaptor then it is at least - * VGA-compatible (surely noone runs CGA, EGA, .... these days?). - * - * These checks are basically to detect headless server boxes. - */ - return (detect_video(__va(0xA0000)) || - detect_video(__va(0xB0000)) || - detect_video(__va(0xB8000))); -} - -/* This is actually code from vgaHWRestore in an old version of XFree86 :-) */ -static void init_vga(void) -{ - /* The following VGA state was saved from a chip in text mode 3. */ - static unsigned char regs[] = { - /* Sequencer registers */ - 0x03, 0x00, 0x03, 0x00, 0x02, - /* CRTC registers */ - 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20, - 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, - 0xb9, 0xa3, 0xff, - /* Graphic registers */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff, - /* Attribute registers */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, - 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00 - }; - - int i, j = 0; - volatile unsigned char tmp; - - if ( !vgacon_enabled ) - return; - - if ( !detect_vga() ) - { - printk("No VGA adaptor detected!\n"); - vgacon_enabled = 0; - return; - } - - tmp = inb(0x3da); - outb(0x00, 0x3c0); - - for ( i = 0; i < 5; i++ ) - outw((regs[j++] << 8) | i, 0x3c4); - - /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */ - outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4); - - for ( i = 0; i < 25; i++ ) - outw((regs[j++] << 8) | i, 0x3d4); - - for ( i = 0; i < 9; i++ ) - outw((regs[j++] << 8) | i, 0x3ce); - - for ( i = 0; i < 21; i++ ) - { - tmp = inb(0x3da); - outb(i, 0x3c0); - outb(regs[j++], 0x3c0); - } - - tmp = inb(0x3da); - outb(0x20, 0x3c0); - - cls(); -} - - -static void put_newline(void) -{ - xpos = 0; - ypos++; - - if (ypos >= LINES) - { - static char zeroarr[2*COLUMNS] = { 0 }; - ypos = LINES-1; - memcpy((char*)video, - (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS); - memcpy((char*)video + (LINES-1)*2*COLUMNS, - zeroarr, 2*COLUMNS); - } -} - - -static void putchar_console(int c) -{ - if ( !vgacon_enabled ) - return; - - if ( c == '\n' ) - { - put_newline(); - } - else - { - video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF; - video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE; - if ( ++xpos >= COLUMNS ) - put_newline(); - } -} - - -void putchar_console_ring(int c) -{ - if ( console_ring.len < CONSOLE_RING_SIZE ) - console_ring.buf[console_ring.len++] = (char)c; -} - - -static inline void __putstr(const char *str) -{ - int c; - serial_puts(sercon_handle, str); - while ( (c = *str++) != '\0' ) - { - putchar_console(c); - putchar_console_ring(c); - } -} - - -void printf(const char *fmt, ...) -{ - va_list args; - char buf[128]; - const char *p = fmt; - unsigned long flags; - - /* - * If the format string contains '%' descriptors then we have to parse it - * before printing it. We parse it into a fixed-length buffer. Long - * strings should therefore _not_ contain '%' characters! - */ - if ( strchr(fmt, '%') != NULL ) - { - va_start(args, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - p = buf; - } - - spin_lock_irqsave(&console_lock, flags); - __putstr(p); - spin_unlock_irqrestore(&console_lock, flags); -} - - -long do_console_write(char *str, unsigned int count) -{ -#define SIZEOF_BUF 256 - unsigned char safe_str[SIZEOF_BUF+1]; - unsigned char single_line[SIZEOF_BUF+2]; - unsigned char line_header[30]; - unsigned char *p; - unsigned char c; - unsigned long flags; - int j; - - if ( count == 0 ) - return 0; - - if ( count > SIZEOF_BUF ) - count = SIZEOF_BUF; - - if ( copy_from_user(safe_str, str, count) ) - return -EFAULT; - safe_str[count] = '\0'; - - sprintf(line_header, "DOM%llu: ", current->domain); - - p = safe_str; - while ( *p != '\0' ) - { - j = 0; - - while ( (c = *p++) != '\0' ) - { - if ( c == '\n' ) - break; - if ( (c < 32) || (c > 126) ) - continue; - single_line[j++] = c; - } - - single_line[j++] = '\n'; - single_line[j++] = '\0'; - - spin_lock_irqsave(&console_lock, flags); - __putstr(line_header); - __putstr(single_line); - spin_unlock_irqrestore(&console_lock, flags); - } - - return 0; -} - - -/********************************* - * Debugging/tracing/error-report. - */ - -void panic(const char *fmt, ...) -{ - va_list args; - char buf[128]; - unsigned long flags; - extern void machine_restart(char *); - - va_start(args, fmt); - (void)vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - /* Spit out multiline message in one go. */ - spin_lock_irqsave(&console_lock, flags); - __putstr("\n****************************************\n"); - __putstr(buf); - __putstr("Aieee! CPU"); - sprintf(buf, "%d", smp_processor_id()); - __putstr(buf); - __putstr(" is toast...\n"); - __putstr("****************************************\n\n"); - __putstr("Reboot in five seconds...\n"); - spin_unlock_irqrestore(&console_lock, flags); - - mdelay(5000); - machine_restart(0); -} - - -void __out_of_line_bug(int line) -{ - printk("kernel BUG in header file at line %d\n", line); - BUG(); - for ( ; ; ) continue; -} - - -/********************************* +/* * Simple syscalls. */ diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index a71aec760e..32786fdfd1 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -42,13 +42,6 @@ key_handler *get_key_handler(u_char key) return key_table[key].handler; } -static void serial_rx(unsigned char c, struct pt_regs *regs) -{ - key_handler *handler; - if ( (handler = get_key_handler(c)) != NULL ) - (*handler)(c, NULL, regs); -} - static void show_handlers(u_char key, void *dev_id, struct pt_regs *regs) { int i; @@ -160,6 +153,4 @@ void initialize_keytable(void) add_key_handler('m', reaudit_pages, "re-audit pages"); add_key_handler('M', audit_all_pages, "audit all pages"); #endif - - serial_set_rx_handler(sercon_handle, serial_rx); } diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c new file mode 100644 index 0000000000..6728a32896 --- /dev/null +++ b/xen/drivers/char/console.c @@ -0,0 +1,498 @@ +/****************************************************************************** + * console.c + * + * Emergency console I/O for Xen and the domain-0 guest OS. + * + * Copyright (c) 2002-2004, K A Fraser. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int xpos, ypos; +static unsigned char *video = __va(0xB8000); + +#define CONSOLE_RING_SIZE 16392 +typedef struct console_ring_st +{ + char buf[CONSOLE_RING_SIZE]; + unsigned int len; +} console_ring_t; +static console_ring_t console_ring; + +static char printk_prefix[16] = ""; + +static int sercon_handle = -1; +static int vgacon_enabled = 0; + +spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + + +/* + * ******************************************************* + * *************** OUTPUT TO VGA CONSOLE ***************** + * ******************************************************* + */ + +/* VGA text (mode 3) definitions. */ +#define COLUMNS 80 +#define LINES 25 +#define ATTRIBUTE 7 + +/* Clear the screen and initialize VIDEO, XPOS and YPOS. */ +static void cls(void) +{ + memset(video, 0, COLUMNS * LINES * 2); + xpos = ypos = 0; + outw(10+(1<<(5+8)), 0x3d4); /* cursor off */ +} + +static int detect_video(void *video_base) +{ + volatile u16 *p = (volatile u16 *)video_base; + u16 saved1 = p[0], saved2 = p[1]; + int video_found = 1; + + p[0] = 0xAA55; + p[1] = 0x55AA; + if ( (p[0] != 0xAA55) || (p[1] != 0x55AA) ) + video_found = 0; + + p[0] = 0x55AA; + p[1] = 0xAA55; + if ( (p[0] != 0x55AA) || (p[1] != 0xAA55) ) + video_found = 0; + + p[0] = saved1; + p[1] = saved2; + + return video_found; +} + +static int detect_vga(void) +{ + /* + * Look at a number of well-known locations. Even if video is not at + * 0xB8000 right now, it will appear there when we set up text mode 3. + * + * We assume if there is any sign of a video adaptor then it is at least + * VGA-compatible (surely noone runs CGA, EGA, .... these days?). + * + * These checks are basically to detect headless server boxes. + */ + return (detect_video(__va(0xA0000)) || + detect_video(__va(0xB0000)) || + detect_video(__va(0xB8000))); +} + +/* This is actually code from vgaHWRestore in an old version of XFree86 :-) */ +static void init_vga(void) +{ + /* The following VGA state was saved from a chip in text mode 3. */ + static unsigned char regs[] = { + /* Sequencer registers */ + 0x03, 0x00, 0x03, 0x00, 0x02, + /* CRTC registers */ + 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20, + 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, + 0xb9, 0xa3, 0xff, + /* Graphic registers */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff, + /* Attribute registers */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, + 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00 + }; + + int i, j = 0; + volatile unsigned char tmp; + + if ( !vgacon_enabled ) + return; + + if ( !detect_vga() ) + { + printk("No VGA adaptor detected!\n"); + vgacon_enabled = 0; + return; + } + + tmp = inb(0x3da); + outb(0x00, 0x3c0); + + for ( i = 0; i < 5; i++ ) + outw((regs[j++] << 8) | i, 0x3c4); + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */ + outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4); + + for ( i = 0; i < 25; i++ ) + outw((regs[j++] << 8) | i, 0x3d4); + + for ( i = 0; i < 9; i++ ) + outw((regs[j++] << 8) | i, 0x3ce); + + for ( i = 0; i < 21; i++ ) + { + tmp = inb(0x3da); + outb(i, 0x3c0); + outb(regs[j++], 0x3c0); + } + + tmp = inb(0x3da); + outb(0x20, 0x3c0); + + cls(); +} + +static void put_newline(void) +{ + xpos = 0; + ypos++; + + if (ypos >= LINES) + { + static char zeroarr[2*COLUMNS] = { 0 }; + ypos = LINES-1; + memcpy((char*)video, + (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS); + memcpy((char*)video + (LINES-1)*2*COLUMNS, + zeroarr, 2*COLUMNS); + } +} + +static void putchar_console(int c) +{ + if ( !vgacon_enabled ) + return; + + if ( c == '\n' ) + { + put_newline(); + } + else + { + video[(xpos + ypos * COLUMNS) * 2] = c & 0xFF; + video[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE; + if ( ++xpos >= COLUMNS ) + put_newline(); + } +} + + +/* + * ******************************************************** + * *************** ACCESS TO CONSOLE RING ***************** + * ******************************************************** + */ + +static void putchar_console_ring(int c) +{ + if ( console_ring.len < CONSOLE_RING_SIZE ) + console_ring.buf[console_ring.len++] = (char)c; +} + +long read_console_ring(unsigned long str, unsigned int count, unsigned cmd) +{ + unsigned int len; + + len = (console_ring.len < count) ? console_ring.len : count; + + if ( copy_to_user((char *)str, console_ring.buf, len) ) + return -EFAULT; + + if ( cmd & CONSOLE_RING_CLEAR ) + console_ring.len = 0; + + return len; +} + + +/* + * ******************************************************* + * *************** ACCESS TO SERIAL LINE ***************** + * ******************************************************* + */ + +/* Characters received over the serial line are buffered for domain 0. */ +#define SERIAL_RX_SIZE 128 +#define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1)) +static char serial_rx_ring[SERIAL_RX_SIZE]; +static unsigned int serial_rx_cons, serial_rx_prod; + +/* CTRL-a switches input direction between Xen and DOM0. */ +#define CTRL_A 0x01 + +static void serial_rx(unsigned char c, struct pt_regs *regs) +{ + key_handler *handler; + unsigned long cpu_mask; + struct task_struct *p; + static char *input_str[2] = { "DOM0", "Xen" }; + static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */ + + if ( c == CTRL_A ) + { + xen_rx = !xen_rx; + printk("*** Serial input -> %s " + "(type 'CTRL-a' to switch input to %s).\n", + input_str[xen_rx], input_str[!xen_rx]); + } + else if ( xen_rx ) + { + if ( (handler = get_key_handler(c)) != NULL ) + (*handler)(c, NULL, regs); + } + else if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE ) + { + serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c; + if ( serial_rx_prod++ == serial_rx_cons ) + { + p = find_domain_by_id(0); /* only DOM0 reads the serial buffer */ + cpu_mask = mark_guest_event(p, _EVENT_CONSOLE); + guest_event_notify(cpu_mask); + put_task_struct(p); + } + } +} + +long do_serial_io(int cmd, int count, char *buffer) +{ + char *kbuf; + long rc; + + /* Only domain-0 may access the emrgency console. */ + if ( current->domain != 0 ) + return -EPERM; + + switch ( cmd ) + { + case SERIALIO_write: + if ( count > (PAGE_SIZE-1) ) + count = PAGE_SIZE-1; + if ( (kbuf = (char *)get_free_page(GFP_KERNEL)) == NULL ) + return -ENOMEM; + kbuf[count] = '\0'; + rc = count; + if ( copy_from_user(kbuf, buffer, count) ) + rc = -EFAULT; + else + serial_puts(sercon_handle, kbuf); + free_page((unsigned long)kbuf); + break; + case SERIALIO_read: + rc = 0; + while ( (serial_rx_cons != serial_rx_prod) && (rc < count) ) + { + if ( put_user(serial_rx_ring[SERIAL_RX_MASK(serial_rx_cons)], + &buffer[rc]) ) + { + rc = -EFAULT; + break; + } + rc++; + serial_rx_cons++; + } + break; + default: + rc = -ENOSYS; + break; + } + + return rc; +} + + +/* + * ***************************************************** + * *************** GENERIC CONSOLE I/O ***************** + * ***************************************************** + */ + +static inline void __putstr(const char *str) +{ + int c; + serial_puts(sercon_handle, str); + while ( (c = *str++) != '\0' ) + { + putchar_console(c); + putchar_console_ring(c); + } +} + +void printf(const char *fmt, ...) +{ + static char buf[1024]; + static int start_of_line = 1; + + va_list args; + char *p, *q; + unsigned long flags; + + spin_lock_irqsave(&console_lock, flags); + + va_start(args, fmt); + (void)vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + p = buf; + while ( (q = strchr(p, '\n')) != NULL ) + { + *q = '\0'; + if ( start_of_line ) + __putstr(printk_prefix); + __putstr(p); + __putstr("\n"); + start_of_line = 1; + p = q + 1; + } + + if ( *p != '\0' ) + { + if ( start_of_line ) + __putstr(printk_prefix); + __putstr(p); + start_of_line = 0; + } + + spin_unlock_irqrestore(&console_lock, flags); +} + +void set_printk_prefix(const char *prefix) +{ + strcpy(printk_prefix, prefix); +} + +/* + * This hypercall is deprecated. Only permit its use in debug environments. + */ +long do_console_write(char *str, unsigned int count) +{ +#ifndef NDEBUG +#define SIZEOF_BUF 256 + unsigned char safe_str[SIZEOF_BUF+1]; + unsigned char single_line[SIZEOF_BUF+2]; + unsigned char line_header[30]; + unsigned char *p; + unsigned char c; + unsigned long flags; + int j; + + if ( count == 0 ) + return 0; + + if ( count > SIZEOF_BUF ) + count = SIZEOF_BUF; + + if ( copy_from_user(safe_str, str, count) ) + return -EFAULT; + safe_str[count] = '\0'; + + sprintf(line_header, "DOM%llu: ", current->domain); + + p = safe_str; + while ( *p != '\0' ) + { + j = 0; + + while ( (c = *p++) != '\0' ) + { + if ( c == '\n' ) + break; + if ( (c < 32) || (c > 126) ) + continue; + single_line[j++] = c; + } + + single_line[j++] = '\n'; + single_line[j++] = '\0'; + + spin_lock_irqsave(&console_lock, flags); + __putstr(line_header); + __putstr(single_line); + spin_unlock_irqrestore(&console_lock, flags); + } + + return 0; +#else + return -ENOSYS; +#endif +} + +void init_console(void) +{ + extern unsigned char opt_console[]; + unsigned char *p; + + /* Where should console output go? */ + for ( p = opt_console; p != NULL; p = strchr(p, ',') ) + { + if ( *p == ',' ) + p++; + if ( strncmp(p, "com", 3) == 0 ) + sercon_handle = parse_serial_handle(p); + else if ( strncmp(p, "vga", 3) == 0 ) + vgacon_enabled = 1; + } + + init_vga(); + + serial_set_rx_handler(sercon_handle, serial_rx); +} + +void console_endboot(int disable_vga) +{ + if ( disable_vga ) + vgacon_enabled = 0; + /* Serial input is directed to DOM0 by default. */ + serial_rx(CTRL_A, NULL); +} + + +/* + * ************************************************************** + * *************** Debugging/tracing/error-report *************** + * ************************************************************** + */ + +void panic(const char *fmt, ...) +{ + va_list args; + char buf[128]; + unsigned long flags; + extern void machine_restart(char *); + + va_start(args, fmt); + (void)vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + /* Spit out multiline message in one go. */ + spin_lock_irqsave(&console_lock, flags); + __putstr("\n****************************************\n"); + __putstr(buf); + __putstr("Aieee! CPU"); + sprintf(buf, "%d", smp_processor_id()); + __putstr(buf); + __putstr(" is toast...\n"); + __putstr("****************************************\n\n"); + __putstr("Reboot in five seconds...\n"); + spin_unlock_irqrestore(&console_lock, flags); + + mdelay(5000); + machine_restart(0); +} + + +void __out_of_line_bug(int line) +{ + printk("kernel BUG in header file at line %d\n", line); + BUG(); + for ( ; ; ) ; +} diff --git a/xen/drivers/char/xen_kbd.c b/xen/drivers/char/keyboard.c similarity index 97% rename from xen/drivers/char/xen_kbd.c rename to xen/drivers/char/keyboard.c index 43260506ed..40fc68cbce 100644 --- a/xen/drivers/char/xen_kbd.c +++ b/xen/drivers/char/keyboard.c @@ -1,3 +1,11 @@ +/****************************************************************************** + * keyboard.c + * + * Driver for IBM PC AT- and PS/2-compatible keyboards. + * + * This file contains portions of code from Linux. + */ + #include #include #include diff --git a/xen/include/hypervisor-ifs/hypervisor-if.h b/xen/include/hypervisor-ifs/hypervisor-if.h index 3506932eaf..ee950c01e1 100644 --- a/xen/include/hypervisor-ifs/hypervisor-if.h +++ b/xen/include/hypervisor-ifs/hypervisor-if.h @@ -42,7 +42,7 @@ /* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */ #define __HYPERVISOR_set_trap_table 0 #define __HYPERVISOR_mmu_update 1 -#define __HYPERVISOR_console_write 2 +#define __HYPERVISOR_console_write 2 /* DEPRECATED */ #define __HYPERVISOR_set_gdt 3 #define __HYPERVISOR_stack_switch 4 #define __HYPERVISOR_set_callbacks 5 @@ -63,6 +63,7 @@ #define __HYPERVISOR_set_timer_op 20 #define __HYPERVISOR_event_channel_op 21 #define __HYPERVISOR_xen_version 22 +#define __HYPERVISOR_serial_io 23 /* And the trap vector is... */ #define TRAP_INSTR "int $0x82" @@ -107,6 +108,7 @@ #define _EVENT_STOP 6 #define _EVENT_EVTCHN 7 #define _EVENT_VBD_UPD 8 +#define _EVENT_CONSOLE 9 /* This is only for domain-0 initial console. */ /* * Virtual addresses beyond this are not modifiable by guest OSes. The @@ -169,6 +171,11 @@ #define SCHEDOP_exit 3 /* Exit and kill this domain. */ #define SCHEDOP_stop 4 /* Stop executing this domain. */ +/* + * Commands to HYPERVISOR_serial_io(). + */ +#define SERIALIO_write 0 +#define SERIALIO_read 1 #ifndef __ASSEMBLY__ diff --git a/xen/include/xeno/console.h b/xen/include/xeno/console.h index d68aa893bb..212199d9a5 100644 --- a/xen/include/xeno/console.h +++ b/xen/include/xeno/console.h @@ -9,28 +9,23 @@ #ifndef __CONSOLE_H__ #define __CONSOLE_H__ +#include + +extern spinlock_t console_lock; + /* * Ownership of console --- currently hardwired to dom0. This is used to see * who gets the PS/2 keyboard/mouse events */ - -extern int sercon_handle; -extern int vgacon_enabled; - #define CONSOLE_ISOWNER(p) (p->domain == 0) #define CONSOLE_OWNER (find_domain_by_id(0)) -#define CONSOLE_RING_SIZE 16392 -#define CONSOLE_RING_CLEAR 1 - -typedef struct console_ring_st -{ - char buf[CONSOLE_RING_SIZE]; - unsigned int len; -} console_ring_t; - -extern console_ring_t console_ring; +void set_printk_prefix(const char *prefix); +#define CONSOLE_RING_CLEAR 1 long read_console_ring(unsigned long, unsigned int, unsigned int); +void init_console(void); +void console_endboot(int disable_vga); + #endif diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c index 7aaac28bca..21149a0f9e 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c @@ -80,22 +80,14 @@ static void nonpriv_conwrite(const char *s, unsigned int count) static void priv_conwrite(const char *s, unsigned int count) { - static char str[256]; - static int pos = 0; - int len; + int rc; - /* We buffer output until we see a newline, or until the buffer is full. */ - while ( count != 0 ) + while ( count > 0 ) { - len = ((sizeof(str) - pos) > count) ? count : sizeof(str) - pos; - memcpy(str + pos, s, len); - pos += len; - s += len; - count -= len; - if ( (pos == sizeof(str)) || (str[pos-1] == '\n') ) + if ( (rc = HYPERVISOR_serial_io(SERIALIO_write, count, s)) > 0 ) { - (void)HYPERVISOR_console_write(str, pos); - pos = 0; + count -= rc; + s += rc; } } } diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h index bce5b9c24d..c6959e107b 100644 --- a/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/hypervisor.h @@ -156,7 +156,6 @@ static inline int HYPERVISOR_set_trap_table(trap_info_t *table) return ret; } - static inline int HYPERVISOR_mmu_update(mmu_update_t *req, int count) { int ret; @@ -175,19 +174,6 @@ static inline int HYPERVISOR_mmu_update(mmu_update_t *req, int count) return ret; } - -static inline int HYPERVISOR_console_write(const char *str, int count) -{ - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) : "0" (__HYPERVISOR_console_write), - "b" (str), "c" (count) : "memory" ); - - - return ret; -} - static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries) { int ret; @@ -454,4 +440,15 @@ static inline int HYPERVISOR_xen_version(int cmd) return ret; } +static inline int HYPERVISOR_serial_io(int cmd, int count, char *str) +{ + int ret; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret) : "0" (__HYPERVISOR_serial_io), + "b" (cmd), "c" (count), "d" (str) : "memory" ); + + return ret; +} + #endif /* __HYPERVISOR_H__ */ diff --git a/xenolinux-2.4.25-sparse/include/asm-xeno/processor.h b/xenolinux-2.4.25-sparse/include/asm-xeno/processor.h index 33bdbd7817..2b290252be 100644 --- a/xenolinux-2.4.25-sparse/include/asm-xeno/processor.h +++ b/xenolinux-2.4.25-sparse/include/asm-xeno/processor.h @@ -188,12 +188,12 @@ extern unsigned long mmu_cr4_features; static inline void set_in_cr4 (unsigned long mask) { - HYPERVISOR_console_write("No set_in_cr4", 13); + BUG(); } static inline void clear_in_cr4 (unsigned long mask) { - HYPERVISOR_console_write("No clear_in_cr4", 15); + BUG(); } /* diff --git a/xenolinux-2.4.25-sparse/kernel/panic.c b/xenolinux-2.4.25-sparse/kernel/panic.c index 6ab619a607..284bd434a3 100644 --- a/xenolinux-2.4.25-sparse/kernel/panic.c +++ b/xenolinux-2.4.25-sparse/kernel/panic.c @@ -110,7 +110,6 @@ NORET_TYPE void panic(const char * fmt, ...) #endif CHECK_EMERGENCY_SYNC #if defined(CONFIG_XENO) - HYPERVISOR_console_write(buf, strlen(buf)); HYPERVISOR_exit(); #endif } diff --git a/xenolinux-2.4.25-sparse/kernel/printk.c b/xenolinux-2.4.25-sparse/kernel/printk.c deleted file mode 100644 index 6cfedd9c02..0000000000 --- a/xenolinux-2.4.25-sparse/kernel/printk.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - * linux/kernel/printk.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Modified to make sys_syslog() more flexible: added commands to - * return the last 4k of kernel messages, regardless of whether - * they've been read or not. Added option to suppress kernel printk's - * to the console. Added hook for sending the console messages - * elsewhere, in preparation for a serial line console (someday). - * Ted Ts'o, 2/11/93. - * Modified for sysctl support, 1/8/97, Chris Horn. - * Fixed SMP synchronization, 08/08/99, Manfred Spraul - * manfreds@colorfullife.com - * Rewrote bits to get rid of console_lock - * 01Mar01 Andrew Morton - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For in_interrupt() */ -#include - -#include - -#if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0) -#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) -#define LOG_BUF_LEN (65536) -#elif defined(CONFIG_ARCH_S390) -#define LOG_BUF_LEN (131072) -#elif defined(CONFIG_SMP) -#define LOG_BUF_LEN (32768) -#else -#define LOG_BUF_LEN (16384) /* This must be a power of two */ -#endif -#else /* CONFIG_LOG_BUF_SHIFT */ -#define LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) -#endif - -#define LOG_BUF_MASK (LOG_BUF_LEN-1) - -#ifndef arch_consoles_callable -#define arch_consoles_callable() (1) -#endif - -/* printk's without a loglevel use this.. */ -#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ - -/* We show everything that is MORE important than this.. */ -#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ -#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ - -DECLARE_WAIT_QUEUE_HEAD(log_wait); - -int console_printk[4] = { - DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ - DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ - MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ - DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ -}; - -int oops_in_progress; - -/* - * console_sem protects the console_drivers list, and also - * provides serialisation for access to the entire console - * driver system. - */ -static DECLARE_MUTEX(console_sem); -struct console *console_drivers; - -/* - * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars - * It is also used in interesting ways to provide interlocking in - * release_console_sem(). - */ -static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; - -static char log_buf[LOG_BUF_LEN]; -#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) - -/* - * The indices into log_buf are not constrained to LOG_BUF_LEN - they - * must be masked before subscripting - */ -static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ - -struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; -static int preferred_console = -1; - -/* Flag: console code may call schedule() */ -static int console_may_schedule; - -/* - * Setup a list of consoles. Called from init/main.c - */ -static int __init console_setup(char *str) -{ - struct console_cmdline *c; - char name[sizeof(c->name)]; - char *s, *options; - int i, idx; - - /* - * Decode str into name, index, options. - */ - if (str[0] >= '0' && str[0] <= '9') { - strcpy(name, "ttyS"); - strncpy(name + 4, str, sizeof(name) - 5); - } else - strncpy(name, str, sizeof(name) - 1); - name[sizeof(name) - 1] = 0; - if ((options = strchr(str, ',')) != NULL) - *(options++) = 0; -#ifdef __sparc__ - if (!strcmp(str, "ttya")) - strcpy(name, "ttyS0"); - if (!strcmp(str, "ttyb")) - strcpy(name, "ttyS1"); -#endif - for(s = name; *s; s++) - if (*s >= '0' && *s <= '9') - break; - idx = simple_strtoul(s, NULL, 10); - *s = 0; - - /* - * See if this tty is not yet registered, and - * if we have a slot free. - */ - for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - preferred_console = i; - return 1; - } - if (i == MAX_CMDLINECONSOLES) - return 1; - preferred_console = i; - c = &console_cmdline[i]; - memcpy(c->name, name, sizeof(c->name)); - c->options = options; - c->index = idx; - return 1; -} - -__setup("console=", console_setup); - -/* - * Commands to do_syslog: - * - * 0 -- Close the log. Currently a NOP. - * 1 -- Open the log. Currently a NOP. - * 2 -- Read from the log. - * 3 -- Read all messages remaining in the ring buffer. - * 4 -- Read and clear all messages remaining in the ring buffer - * 5 -- Clear ring buffer. - * 6 -- Disable printk's to console - * 7 -- Enable printk's to console - * 8 -- Set level of messages printed to console - * 9 -- Return number of unread characters in the log buffer - */ -int do_syslog(int type, char * buf, int len) -{ - unsigned long i, j, limit, count; - int do_clear = 0; - char c; - int error = 0; - - switch (type) { - case 0: /* Close log */ - break; - case 1: /* Open log */ - break; - case 2: /* Read from log */ - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - error = verify_area(VERIFY_WRITE,buf,len); - if (error) - goto out; - error = wait_event_interruptible(log_wait, (log_start - log_end)); - if (error) - goto out; - i = 0; - spin_lock_irq(&logbuf_lock); - while ((log_start != log_end) && i < len) { - c = LOG_BUF(log_start); - log_start++; - spin_unlock_irq(&logbuf_lock); - __put_user(c,buf); - buf++; - i++; - spin_lock_irq(&logbuf_lock); - } - spin_unlock_irq(&logbuf_lock); - error = i; - break; - case 4: /* Read/clear last kernel messages */ - do_clear = 1; - /* FALL THRU */ - case 3: /* Read last kernel messages */ - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - error = verify_area(VERIFY_WRITE,buf,len); - if (error) - goto out; - count = len; - if (count > LOG_BUF_LEN) - count = LOG_BUF_LEN; - spin_lock_irq(&logbuf_lock); - if (count > logged_chars) - count = logged_chars; - if (do_clear) - logged_chars = 0; - limit = log_end; - /* - * __put_user() could sleep, and while we sleep - * printk() could overwrite the messages - * we try to copy to user space. Therefore - * the messages are copied in reverse. - */ - for(i=0;i < count;i++) { - j = limit-1-i; - if (j+LOG_BUF_LEN < log_end) - break; - c = LOG_BUF(j); - spin_unlock_irq(&logbuf_lock); - __put_user(c,&buf[count-1-i]); - spin_lock_irq(&logbuf_lock); - } - spin_unlock_irq(&logbuf_lock); - error = i; - if(i != count) { - int offset = count-error; - /* buffer overflow during copy, correct user buffer. */ - for(i=0;i 8) - goto out; - if (len < minimum_console_loglevel) - len = minimum_console_loglevel; - spin_lock_irq(&logbuf_lock); - console_loglevel = len; - spin_unlock_irq(&logbuf_lock); - error = 0; - break; - case 9: /* Number of chars in the log buffer */ - spin_lock_irq(&logbuf_lock); - error = log_end - log_start; - spin_unlock_irq(&logbuf_lock); - break; - default: - error = -EINVAL; - break; - } -out: - return error; -} - -asmlinkage long sys_syslog(int type, char * buf, int len) -{ - if ((type != 3) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - return do_syslog(type, buf, len); -} - -/* - * Call the console drivers on a range of log_buf - */ -static void __call_console_drivers(unsigned long start, unsigned long end) -{ - struct console *con; - - for (con = console_drivers; con; con = con->next) { - if ((con->flags & CON_ENABLED) && con->write) - con->write(con, &LOG_BUF(start), end - start); - } -} - -/* - * Write out chars from start to end - 1 inclusive - */ -static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) -{ - if (msg_log_level < console_loglevel && console_drivers && start != end) { - if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { - /* wrapped write */ - __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN); - __call_console_drivers(0, end & LOG_BUF_MASK); - } else { - __call_console_drivers(start, end); - } - } -} - -/* - * Call the console drivers, asking them to write out - * log_buf[start] to log_buf[end - 1]. - * The console_sem must be held. - */ -static void call_console_drivers(unsigned long start, unsigned long end) -{ - unsigned long cur_index, start_print; - static int msg_level = -1; - - if (((long)(start - end)) > 0) - BUG(); - - cur_index = start; - start_print = start; - while (cur_index != end) { - if ( msg_level < 0 && - ((end - cur_index) > 2) && - LOG_BUF(cur_index + 0) == '<' && - LOG_BUF(cur_index + 1) >= '0' && - LOG_BUF(cur_index + 1) <= '7' && - LOG_BUF(cur_index + 2) == '>') - { - msg_level = LOG_BUF(cur_index + 1) - '0'; - cur_index += 3; - start_print = cur_index; - } - while (cur_index != end) { - char c = LOG_BUF(cur_index); - cur_index++; - - if (c == '\n') { - if (msg_level < 0) { - /* - * printk() has already given us loglevel tags in - * the buffer. This code is here in case the - * log buffer has wrapped right round and scribbled - * on those tags - */ - msg_level = default_message_loglevel; - } - _call_console_drivers(start_print, cur_index, msg_level); - msg_level = -1; - start_print = cur_index; - break; - } - } - } - _call_console_drivers(start_print, end, msg_level); -} - -static void emit_log_char(char c) -{ - LOG_BUF(log_end) = c; - log_end++; - if (log_end - log_start > LOG_BUF_LEN) - log_start = log_end - LOG_BUF_LEN; - if (log_end - con_start > LOG_BUF_LEN) - con_start = log_end - LOG_BUF_LEN; - if (logged_chars < LOG_BUF_LEN) - logged_chars++; -} - -/* - * This is printk. It can be called from any context. We want it to work. - * - * We try to grab the console_sem. If we succeed, it's easy - we log the output and - * call the console drivers. If we fail to get the semaphore we place the output - * into the log buffer and return. The current holder of the console_sem will - * notice the new output in release_console_sem() and will send it to the - * consoles before releasing the semaphore. - * - * One effect of this deferred printing is that code which calls printk() and - * then changes console_loglevel may break. This is because console_loglevel - * is inspected when the actual printing occurs. - */ -asmlinkage int printk(const char *fmt, ...) -{ - va_list args; - unsigned long flags; - int printed_len; - char *p; - static char printk_buf[1024]; - static int log_level_unknown = 1; - - if (oops_in_progress) { - /* If a crash is occurring, make sure we can't deadlock */ - spin_lock_init(&logbuf_lock); - /* And make sure that we print immediately */ - init_MUTEX(&console_sem); - } - - /* This stops the holder of console_sem just where we want him */ - spin_lock_irqsave(&logbuf_lock, flags); - - /* Emit the output into the temporary buffer */ - va_start(args, fmt); - printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); - va_end(args); - -#if 0 - /* Useful if things are going wrong very early in the day. */ - (void)HYPERVISOR_console_write(printk_buf, printed_len); -#endif - - /* - * Copy the output into log_buf. If the caller didn't provide - * appropriate log level tags, we insert them here - */ - for (p = printk_buf; *p; p++) { - if (log_level_unknown) { - if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { - emit_log_char('<'); - emit_log_char(default_message_loglevel + '0'); - emit_log_char('>'); - } - log_level_unknown = 0; - } - emit_log_char(*p); - if (*p == '\n') - log_level_unknown = 1; - } - - if (!arch_consoles_callable()) { - /* - * On some architectures, the consoles are not usable - * on secondary CPUs early in the boot process. - */ - spin_unlock_irqrestore(&logbuf_lock, flags); - goto out; - } - if (!down_trylock(&console_sem)) { - /* - * We own the drivers. We can drop the spinlock and let - * release_console_sem() print the text - */ - spin_unlock_irqrestore(&logbuf_lock, flags); - console_may_schedule = 0; - release_console_sem(); - } else { - /* - * Someone else owns the drivers. We drop the spinlock, which - * allows the semaphore holder to proceed and to call the - * console drivers with the output which we just produced. - */ - spin_unlock_irqrestore(&logbuf_lock, flags); - } -out: - return printed_len; -} -EXPORT_SYMBOL(printk); - -/** - * acquire_console_sem - lock the console system for exclusive use. - * - * Acquires a semaphore which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. - * - * Can sleep, returns nothing. - */ -void acquire_console_sem(void) -{ - if (in_interrupt()) - BUG(); - down(&console_sem); - console_may_schedule = 1; -} -EXPORT_SYMBOL(acquire_console_sem); - -/** - * release_console_sem - unlock the console system - * - * Releases the semaphore which the caller holds on the console system - * and the console driver list. - * - * While the semaphore was held, console output may have been buffered - * by printk(). If this is the case, release_console_sem() emits - * the output prior to releasing the semaphore. - * - * If there is output waiting for klogd, we wake it up. - * - * release_console_sem() may be called from any context. - */ -void release_console_sem(void) -{ - unsigned long flags; - unsigned long _con_start, _log_end; - unsigned long must_wake_klogd = 0; - - for ( ; ; ) { - spin_lock_irqsave(&logbuf_lock, flags); - must_wake_klogd |= log_start - log_end; - if (con_start == log_end) - break; /* Nothing to print */ - _con_start = con_start; - _log_end = log_end; - con_start = log_end; /* Flush */ - spin_unlock_irqrestore(&logbuf_lock, flags); - call_console_drivers(_con_start, _log_end); - } - console_may_schedule = 0; - up(&console_sem); - spin_unlock_irqrestore(&logbuf_lock, flags); - if (must_wake_klogd && !oops_in_progress) - wake_up_interruptible(&log_wait); -} - -/** console_conditional_schedule - yield the CPU if required - * - * If the console code is currently allowed to sleep, and - * if this CPU should yield the CPU to another task, do - * so here. - * - * Must be called within acquire_console_sem(). - */ -void console_conditional_schedule(void) -{ - if (console_may_schedule && current->need_resched) { - set_current_state(TASK_RUNNING); - schedule(); - } -} - -void console_print(const char *s) -{ - printk(KERN_EMERG "%s", s); -} -EXPORT_SYMBOL(console_print); - -void console_unblank(void) -{ - struct console *c; - - /* - * Try to get the console semaphore. If someone else owns it - * we have to return without unblanking because console_unblank - * may be called in interrupt context. - */ - if (down_trylock(&console_sem) != 0) - return; - console_may_schedule = 0; - for (c = console_drivers; c != NULL; c = c->next) - if ((c->flags & CON_ENABLED) && c->unblank) - c->unblank(); - release_console_sem(); -} -EXPORT_SYMBOL(console_unblank); - -/* - * The console driver calls this routine during kernel initialization - * to register the console printing procedure with printk() and to - * print any messages that were printed by the kernel before the - * console driver was initialized. - */ -void register_console(struct console * console) -{ - int i; - unsigned long flags; - - /* - * See if we want to use this console driver. If we - * didn't select a console we take the first one - * that registers here. - */ - if (preferred_console < 0) { - if (console->index < 0) - console->index = 0; - if (console->setup == NULL || - console->setup(console, NULL) == 0) { - console->flags |= CON_ENABLED | CON_CONSDEV; - preferred_console = 0; - } - } - - /* - * See if this console matches one we selected on - * the command line. - */ - for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) { - if (strcmp(console_cmdline[i].name, console->name) != 0) - continue; - if (console->index >= 0 && - console->index != console_cmdline[i].index) - continue; - if (console->index < 0) - console->index = console_cmdline[i].index; - if (console->setup && - console->setup(console, console_cmdline[i].options) != 0) - break; - console->flags |= CON_ENABLED; - console->index = console_cmdline[i].index; - if (i == preferred_console) - console->flags |= CON_CONSDEV; - break; - } - - if (!(console->flags & CON_ENABLED)) - return; - - /* - * Put this console in the list - keep the - * preferred driver at the head of the list. - */ - acquire_console_sem(); - if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { - console->next = console_drivers; - console_drivers = console; - } else { - console->next = console_drivers->next; - console_drivers->next = console; - } - if (console->flags & CON_PRINTBUFFER) { - /* - * release_console_sem() will print out the buffered messages for us. - */ - spin_lock_irqsave(&logbuf_lock, flags); - con_start = log_start; - spin_unlock_irqrestore(&logbuf_lock, flags); - } - release_console_sem(); -} -EXPORT_SYMBOL(register_console); - -int unregister_console(struct console * console) -{ - struct console *a,*b; - int res = 1; - - acquire_console_sem(); - if (console_drivers == console) { - console_drivers=console->next; - res = 0; - } else { - for (a=console_drivers->next, b=console_drivers ; - a; b=a, a=b->next) { - if (a == console) { - b->next = a->next; - res = 0; - break; - } - } - } - - /* If last console is removed, we re-enable picking the first - * one that gets registered. Without that, pmac early boot console - * would prevent fbcon from taking over. - */ - if (console_drivers == NULL) - preferred_console = -1; - - - release_console_sem(); - return res; -} -EXPORT_SYMBOL(unregister_console); - -/** - * tty_write_message - write a message to a certain tty, not just the console. - * - * This is used for messages that need to be redirected to a specific tty. - * We don't put it into the syslog queue right now maybe in the future if - * really needed. - */ -void tty_write_message(struct tty_struct *tty, char *msg) -{ - if (tty && tty->driver.write) - tty->driver.write(tty, 0, msg, strlen(msg)); - return; -} -- 2.30.2